﻿using Chloe;
using Gate.ExpressionBuilder.Enums;
using System;
using System.Linq.Expressions;
using System.Reflection;

namespace Gate.Chloe.ExpressionBuilder
{
    /// <summary>
    /// 表达式生成器
    /// </summary>
    public partial class ChloeExpressionBuilder : Gate.ExpressionBuilder.ExpressionBuilder
    {
        /// <summary>
        /// 对值进行包装
        /// </summary>
        /// <param name="data">目标值</param>
        /// <returns></returns>
        override public Expression GetConstantExpression(object data)
        {
            object wrapper = WrapValue(data);
            ConstantExpression wrapperConstantExp = Expression.Constant(wrapper);
            Expression expression = Expression.MakeMemberAccess(wrapperConstantExp, wrapper.GetType().GetProperty("Value"));
            return expression;
        }
        /// <summary>
        /// 包装值,防止注入
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private object WrapValue(object data)
        {
            Type wrapperType = typeof(ConstantWrapper<>).MakeGenericType(data.GetType());
            ConstructorInfo constructor = wrapperType.GetConstructor(new Type[] { data.GetType() });
            return constructor.Invoke(new object[] { data });
        }


        /// <summary>
        /// 生成针对字符串对比的方法的表达式树
        /// </summary>
        /// <param name="lExpression">左值表达式</param>
        /// <param name="rExpression">右值表达式</param>
        /// <param name="conditionsType">比较类型</param>
        /// <returns></returns>
        override public Expression GetSpecialExpression(Expression lExpression, Expression rExpression, Conditions conditionsType)
        {
            MethodCallExpression predicateBody = null;
            if (lExpression.Type == typeof(String))
            {
                MethodInfo method = typeof(Sql).GetMethod("Compare");
                method = method.MakeGenericMethod(lExpression.Type);
                CompareType compareType;
                switch (conditionsType)
                {
                    case Conditions.LessThan://小于
                        compareType = CompareType.lt;
                        break;
                    case Conditions.LessThanOrEqual://小于等于
                        compareType = CompareType.lte;
                        break;
                    case Conditions.GreaterThan://大于
                        compareType = CompareType.gt;
                        break;
                    case Conditions.GreaterThanOrEqual://大于等于
                        compareType = CompareType.gte;
                        break;
                    default:
                        return null;
                }
                ConstantExpression compareTypeEnum = Expression.Constant(compareType, typeof(CompareType));
                //比对结果
                predicateBody = Expression.Call(method, lExpression, compareTypeEnum, rExpression);
            }
            return predicateBody;
        }
    }
}
